package com.zys.http.processor;

import cn.hutool.core.text.CharSequenceUtil;
import com.intellij.ide.projectView.PresentationData;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.psi.NavigatablePsiElement;
import com.intellij.psi.PsiElement;
import com.zys.http.constant.HttpEnum;
import com.zys.http.entity.param.ParamProperty;
import com.zys.http.entity.tree.MethodNodeData;
import com.zys.http.extension.gutter.HttpLineMarkerInfo;
import com.zys.http.extension.search.everywhere.GotoApiItem;
import com.zys.http.processor.basic.PostmanProcessor;
import com.zys.http.processor.jaxrs.JaxRsJavaProcessor;
import com.zys.http.processor.jaxrs.JaxRsKotlinProcessor;
import com.zys.http.processor.spring.SpringJavaProcessor;
import com.zys.http.processor.spring.SpringKotlinProcessor;
import com.zys.http.tool.ThreadTool;
import com.zys.http.ui.icon.HttpIcons;
import com.zys.http.ui.tree.node.MethodNode;
import lombok.SneakyThrows;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.KotlinLanguage;

import javax.swing.*;
import java.util.*;

/**
 * @author zys
 * @since 2025-01-20
 */
public class ProcessorContext {
    private static final Map<String, List<CoreProcessor>> PROCESSOR_MAP = new HashMap<>();

    static {
        // 索引 0-Spring 1-JaxRs
        PROCESSOR_MAP.put(JavaLanguage.INSTANCE.getDisplayName(), List.of(SpringJavaProcessor.INSTANCE, JaxRsJavaProcessor.INSTANCE));
        PROCESSOR_MAP.put(KotlinLanguage.INSTANCE.getDisplayName(), List.of(SpringKotlinProcessor.INSTANCE, JaxRsKotlinProcessor.INSTANCE));
    }

    private static List<CoreProcessor> getCoreProcessors(PsiElement element) {
        return Optional.ofNullable(PROCESSOR_MAP.get(element.getLanguage().getDisplayName())).orElse(new ArrayList<>());
    }

    public static Collection<Module> projectModules(Project project) {
        return PROCESSOR_MAP.get(JavaLanguage.INSTANCE.getDisplayName()).get(0).projectModules(project);
    }

    public static String modulePath(Module module, Project project) {
        return PROCESSOR_MAP.get(JavaLanguage.INSTANCE.getDisplayName()).get(0).modulePath(module, project);
    }

    public static String modulePort(@NotNull Module module, Project project) {
        return PROCESSOR_MAP.get(JavaLanguage.INSTANCE.getDisplayName()).get(0).modulePort(module, project);
    }

    public static String getGradleParentModuleName(Module module) {
        return PROCESSOR_MAP.get(JavaLanguage.INSTANCE.getDisplayName()).get(0).getGradleParentModuleName(module);
    }

    @SneakyThrows
    public static List<? extends PsiElement> moduleControllers(Project project, Module module, @NotNull List<HttpEnum.Language> languages) {
        return ReadAction.nonBlocking(() -> {
            if (languages.isEmpty() || languages.size() >= HttpEnum.Language.values().length) {
                return PROCESSOR_MAP.values().stream().flatMap(Collection::stream).map(o -> o.moduleControllers(module, project)).flatMap(Collection::stream).toList();
            } else if (languages.contains(HttpEnum.Language.JAVA)) {
                return PROCESSOR_MAP.get(JavaLanguage.INSTANCE.getDisplayName()).stream().map(o -> o.moduleControllers(module, project)).flatMap(Collection::stream).toList();
            }
            return PROCESSOR_MAP.get(KotlinLanguage.INSTANCE.getDisplayName()).stream().map(o -> o.moduleControllers(module, project)).flatMap(Collection::stream).toList();
        }).submit(ThreadTool.getExecutor()).get();
    }

    public static String controllerPackageName(PsiElement element) {
        List<CoreProcessor> coreProcessors = getCoreProcessors(element);
        return coreProcessors.isEmpty() ? null : coreProcessors.get(0).controllerPackageName(element);
    }

    public static String controllerSwagger(PsiElement element) {
        List<CoreProcessor> coreProcessors = getCoreProcessors(element);
        return coreProcessors.isEmpty() ? "" : getCoreProcessors(element).get(0).controllerSwagger(element);
    }

    public static boolean isSpringMethod(PsiElement element) {
        List<CoreProcessor> coreProcessors = getCoreProcessors(element);
        return !coreProcessors.isEmpty() && coreProcessors.get(0).isTargetMethod(element);
    }

    public static boolean isJaxRsMethod(PsiElement element) {
        List<CoreProcessor> coreProcessors = getCoreProcessors(element);
        return !coreProcessors.isEmpty() && coreProcessors.get(1).isTargetMethod(element);
    }

    @SneakyThrows
    public static List<MethodNode> methodNodes(PsiElement element, String modulePath) {
        if (Objects.isNull(element)) {
            return Collections.emptyList();
        }
        return ReadAction.nonBlocking(() -> PROCESSOR_MAP.values().stream()
                .flatMap(Collection::stream)
                .map(o -> o.methodNodes(element, modulePath))
                .flatMap(Collection::stream)
                .toList()
        ).submit(ThreadTool.getExecutor()).get();
    }

    public static Map<String, ParamProperty> methodParametersParse(@NotNull PsiElement element, boolean isJsonPretty) {
        if (isSpringMethod(element)) {
            return getCoreProcessors(element).get(0).methodParametersParse(element, isJsonPretty);
        }
        if (isJaxRsMethod(element)) {
            return getCoreProcessors(element).get(1).methodParametersParse(element, isJsonPretty);
        }
        return Collections.emptyMap();
    }

    public static List<PostmanProcessor.PostmanItem> postmanControllerItems(PsiElement psiElement, String contextPath) {
        return PROCESSOR_MAP.values().stream()
                .flatMap(Collection::stream)
                .map(o -> o.postmanControllerItems(psiElement, contextPath))
                .flatMap(Collection::stream)
                .toList();
    }

    public static String apiPath(@NotNull PsiElement element, Project project) {
        return getCoreProcessors(element).stream()
                .map(o -> o.apiPath(element, project))
                .filter(CharSequenceUtil::isNotEmpty)
                .findFirst().orElse(null);
    }

    public static HttpLineMarkerInfo createLineMarkerInfo(PsiElement element) {
        return getCoreProcessors(element).stream()
                .map(o -> o.createLineMarkerInfo(element))
                .filter(Objects::nonNull)
                .findFirst()
                .orElse(null);
    }

    public static PresentationData getPresentationData(@NotNull GotoApiItem gotoApiItem) {
        MethodNodeData methodNodeData = gotoApiItem.methodNodeData();
        NavigatablePsiElement element = methodNodeData.getPsiElement();
        Icon icon = HttpIcons.HttpMethod.getHttpMethodIcon(methodNodeData.getHttpMethod());
        String location = getCoreProcessors(element).stream()
                .map(o -> o.getPresentationLocation(element))
                .filter(CharSequenceUtil::isNotEmpty)
                .findFirst()
                .orElse("");
        return new PresentationData(gotoApiItem.getName(), location, icon, null);
    }


}
